package com.health.es.temp;

import com.health.es.util.SearchHit;
import com.health.es.util.SearchHits;
import com.health.es.util.query.NativeSearchQuery;
import com.health.es.util.query.Query;
import com.health.trans.common.entity.PageResponse;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.aggregations.Aggregations;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;

import static com.health.es.temp.EsHelper.getBoolQueryBuilder;

/**
 * ES分页辅助类
 *
 * @param <T>
 * @author nqlz
 */
@Data
@AllArgsConstructor
@Accessors(chain = true)
@ApiModel("分页对象")
@NoArgsConstructor
public class EsPage<T> {

    /**
     * 当前页的位置
     */
    @ApiModelProperty("当前页")
    private int page = 1;
    /**
     * 页面大小
     */
    @ApiModelProperty("页面大小")
    private int size = 20;
    /**
     * 当前表中总条目数量
     */
    @ApiModelProperty("页面大小")
    private long count;
    /**
     * 返回数据
     */
    @ApiModelProperty("返回数据")
    private List<T> data;
    /**
     * 总页数
     */
    @ApiModelProperty("总页数")
    private int totalPage;
    /**
     * 检索的起始位置,spring-data 规范为 page-1 不用计算起始索引
     */
    @ApiModelProperty(hidden = true)
    private transient int from = 0;

    /**
     * 排序
     */
    @ApiModelProperty(hidden = true)
    private transient Sort sort = Sort.unsorted();

    @ApiModelProperty(hidden = true)
    private Aggregations aggregations;

    public EsPage(int page, int size, Sort sort) {
        this.page = page;
        this.size = size;
        this.sort = sort;
    }

    public EsPage(int page, int size) {
        this.page = page;
        this.size = size;
        this.from = (Math.max((this.page - 1), 0));
    }

    public EsPage<T> setCount(long count) {
        this.count = count;
        this.count();
        return this;
    }

    public void count() {
        if (this.size < 1) {
            this.size = 20;
        }
        int totalPageTemp = (int) count <= size ? 1 : (int) (count % size > 0 ? count / size + 1 : count / size);
        if (totalPageTemp <= 0) {
            totalPageTemp = 1;
        }
        //总页数
        this.totalPage = totalPageTemp;

        if (this.totalPage < this.page) {
            this.page = this.totalPage;
        }
        if (this.page < 1) {
            this.page = 1;
        }
        //起始位置
        this.from = (Math.max((this.page - 1), 0));
    }

    private EsPage<T> getEsPage(Class<T> tClass, Pageable pageable, QueryBuilder... builders) {
        QueryBuilder builder = builders.length == 1 ? builders[0] : getBoolQueryBuilder(builders);
        NativeSearchQuery query = new NativeSearchQuery(builder).setPageable(pageable);
        SearchHits<T> search = EsHelper.operations.search(query, tClass);
        return this.setData(search.map(SearchHit::getContent).toList()).setCount(EsHelper.operations.count(query, tClass));
    }

    public EsPage<T> getEsPage(Class<T> tClass, Query query, Consumer<T> objectFunction) {
        query.setPageable(PageRequest.of(from, size, sort));
        SearchHits<T> search = EsHelper.operations.search(query, tClass);
        List<T> tList = search.map(SearchHit::getContent).toList();
        if (Objects.nonNull(objectFunction)) {
            tList.parallelStream().forEach(objectFunction);
        }
        return this.setData(tList).setAggregations(search.getAggregations());
    }

    public EsPage<T> getEsPage(Class<T> tClass, QueryBuilder... builders) {
        return getEsPage(tClass, PageRequest.of(from, size, sort), builders);
    }

    public EsPage<T> getEsPage(Class<T> tClass, Sort sort, QueryBuilder... builders) {
        return getEsPage(tClass, PageRequest.of(from, size, sort), builders);
    }

    public PageResponse<T> response() {
        return PageResponse.success(count, data);
    }

    public <R> PageResponse<T> response(Function<List<T>, List<R>> listFunction) {
        return PageResponse.success(count, listFunction.apply(data));
    }

}
